// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: Implementation of CBinaryBehavior.
//   $Id$

#include "stdafx.h"
#include <new>
#include "XForms.h"
#include "BinaryBehavior.h"
#include "XFormsApp.h"
#include "eventmsg.h"
#include "MSHTMLDOMPurger.h"
#include <dom2Events_i.c>

extern CXFormsApp theApp;

// Bug 880 - To improve the performance of CBinaryBehavior::getCurrentStyleAsText() I've change the string 
// from a ATL::CComBSTR to a std::wstring as it appears to be faster. In addition I've changed it to use the 
// global wstring to same on reallocation of memory. 
std::wstring g_sStyleAsText;
// Found that in most cases the style text was under 2000 character in length.
const int g_nMinSizeStyleAsText = 2000;
#define CATCH_COPYSTYLE_FUCKUPS 0
/////////////////////////////////////////////////////////////////////////////
// CBinaryBehavior

CBinaryBehavior::CBinaryBehavior()
{
}

CBinaryBehavior::~CBinaryBehavior()
{
/*	CComPtr<IHTMLDocument> pDoc;
	GetViewlinkDoc(&pDoc);
	CComQIPtr<IHTMLDocument2> pDoc2(pDoc);
	if(pDoc2)
	{
		pDoc2->write(0);
		pDoc2->close();
	}*/
	//probably unneeded.
	SetViewlinkProperties(0,VARIANT_FALSE,VARIANT_FALSE,VARIANT_FALSE);
}

STDMETHODIMP CBinaryBehavior::Init(IElementBehaviorSite* pBehaviorSite)
{
	#ifdef 	AFX_MANAGE_STATE
		//IF the application uses MFC, maintain the state.
		AFX_MANAGE_STATE(AfxGetStaticModuleState())
	#endif

	HRESULT hr = E_FAIL;

#ifndef _DEBUG
	try {
#endif
		// Cache the IElementBehaviorSite interface pointer.
		m_pSite = pBehaviorSite;
		if(m_pSite) {
			CComQIPtr<IElementBehaviorSiteOM2> pOMSite;
			pOMSite = m_pSite;
			if(pOMSite) {
				// Get the defaults
				pOMSite->GetDefaults(&m_pDefaults);
				if(m_pDefaults)
					m_pDefaults->put_tabStop(VARIANT_TRUE);
				m_pSiteOM = m_pSite;
				if(m_pSiteOM)
					hr = InitBehaviour(); 
			}
		}
#ifndef _DEBUG
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
#endif

	return hr;
}

STDMETHODIMP CBinaryBehavior::Detach()
{
	#ifdef 	AFX_MANAGE_STATE
		//IF the application uses MFC, maintain the state.
		AFX_MANAGE_STATE(AfxGetStaticModuleState())
	#endif
	HRESULT	hr = S_OK;
#ifndef _DEBUG
	try {
#endif
		CComPtr<IHTMLElement> pMaster;
		GetMasterElement(&pMaster);
		if(pMaster)
			pMaster->setAttribute(L"viewlinkDocument",CComVariant(0),3);

		//Clean the viewlink document.
		CComPtr<IHTMLDocument> pDoc;
		if(m_pDefaults)
		{
			m_pDefaults->get_viewLink(&pDoc);
			if(pDoc)
			{
/*				CMSHTMLDOMPurger * pPurger = CMSHTMLDOMPurger::GetPurger();
				pPurger->Purge(pDoc);
*/				CComQIPtr<IHTMLDocument2> pDoc2 = pDoc;
				if(pDoc2)
				{
					CComVariant vt;
					hr = pDoc2->open(NULL,vt,vt,vt,NULL);
					pDoc2->write(0); 
					
					pDoc2->close(); 
				}
			}
		}
#ifndef _DEBUG
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
#endif
	return hr;
}

STDMETHODIMP CBinaryBehavior::Notify(LONG lEvent, VARIANT* /*pVar*/)
{
	#ifdef 	AFX_MANAGE_STATE
		//IF the application uses MFC, maintain the state.
		AFX_MANAGE_STATE(AfxGetStaticModuleState())
	#endif
	HRESULT hr = S_OK;

#ifndef _DEBUG
	try {
#endif
		switch (lEvent)
		{
			case BEHAVIOREVENT_CONTENTREADY:

				/*
				* The end tag of the master element has now been parsed, which means we can access the
				* element and its children. Note that you cannot access the DOM yet, until we've had
				* DOCUMENTREADY
				*/
				{
					CComPtr<IHTMLElement> pElem;
					if (m_pSite && S_OK == m_pSite->GetElement(&pElem))
						hr = ElementReady();
				}
				break;

			case BEHAVIOREVENT_DOCUMENTREADY:

				/*
				* The entire HTML document has been parsed, which means that we can access the DOM
				*/

				hr = DocumentReady();
				break;

			default:
				break;
		} // switch ( event )
#ifndef _DEBUG
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
#endif
	return hr;
}

HRESULT CBinaryBehavior::DocumentReady()
{
	HRESULT hr = S_OK;

	return hr;
}

HRESULT CBinaryBehavior::ElementReady()
{
	HRESULT hr = S_OK;

	return hr;
}

template < class T > 
HRESULT _copyStyle( IHTMLElement2 * pSource, T *pTarget )
{
	HRESULT hr = E_FAIL;
	if(pSource && pTarget)
	{
		//Temp method, only copies style set by 
		//	DOM and in style attributes.
		//temp handling, currentstyle is the correct method, 
		//	available through IHTMLElement2
		//	I should probably have an overload, allowing 
		//	call by IHTMLElement IHTMLElement
		CComQIPtr<IHTMLElement> pSEl = pSource;
		if(pSEl) {
			CComPtr<IHTMLStyle> pSS;
			pSEl->get_style(&pSS);
			if(pSS) {
				CComBSTR sStyle;
				pSS->get_cssText(&sStyle);
				CComPtr<IHTMLStyle> pTS;
				pTarget->get_style(&pTS);
				if(pTS) {
					pTS->put_cssText(sStyle);
					hr = S_OK;
				}
			}
		}

	/*	TODO: implement the following method using currentStyle

		IHTMLCurrentStyle *pCS = NULL;
		IHTMLStyle * pS = NULL;

		//get the appropriate style objects

		pSource->get_currentStyle(&pCS);
		pTarget->get_style(&pS);
		
		//copy BSTR properties
		
		//copy VARIANT properties

		//copy VARIANT_BOOL properties
		
		//Get next interface.


		//clean up
		pCS->Release();
		pS->Release();
		return hr;

	  */
	}
	return hr;
}


HRESULT CBinaryBehavior::copyStyle( IHTMLElement2 * pSource, IHTMLElement *pTarget )
{
	return _copyStyle(pSource,pTarget);
}
HRESULT CBinaryBehavior::copyStyle( IHTMLElement2 * pSource, IHTMLElementDefaults *pTarget )
{
	return _copyStyle(pSource,pTarget);
}

HRESULT CBinaryBehavior::getCurrentStyleAsText(IHTMLElement2 * pSource, BSTR * pbsRetVal)
{
	//This is an annoyingly long function, 
	//	it plays the same role as get_cssText 
	//	does on IHTMLStyle but using IHTMLCurrentStyle.
	HRESULT hr = E_FAIL;
	CComPtr<IHTMLCurrentStyle> pStyle;
	hr = pSource->get_currentStyle(&pStyle);
	CComBSTR sBuf;
	CComVariant vtBuf;
    // Bug 880 - Now that the string is global we need to clear it so that we're not appending to the 
	// previous CSS text. wstring::clear() clears the string but doesn't free up the resources.
	g_sStyleAsText.clear();
	// Bug 880 - I've found that the CSS text is normally under the 2000 characters in length so if
	// we reserve that we shouldn't have to keep reallocating memory. I also found that it 
	// sames a little bit of time doing this check.
	if(g_sStyleAsText.capacity() < g_nMinSizeStyleAsText)
		g_sStyleAsText.reserve(g_nMinSizeStyleAsText);
	
	BSTR bsBuf;
	if(SUCCEEDED(hr) && pStyle)
	{
		pStyle->get_accelerator(&bsBuf);
		g_sStyleAsText += L"accelerator:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_backgroundAttachment(&bsBuf);
		g_sStyleAsText += L";background-attachment:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle->get_backgroundColor(&vtBuf);
		g_sStyleAsText += L";background-color:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();


		pStyle->get_backgroundImage(&bsBuf);
		g_sStyleAsText += L";background-image:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle->get_backgroundPositionX(&vtBuf);
		g_sStyleAsText += L";background-position-x:";
		if(vtBuf.bstrVal) {
			g_sStyleAsText += vtBuf.bstrVal;
		}
		vtBuf.Clear();


		vtBuf.vt = VT_BSTR;
		pStyle->get_backgroundPositionY(&vtBuf);
		g_sStyleAsText += L";background-position-y:";
		if(vtBuf.bstrVal) {
			g_sStyleAsText += vtBuf.bstrVal;
		}
		vtBuf.Clear();


		pStyle->get_backgroundRepeat(&bsBuf);
		g_sStyleAsText += L";background-repeat:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_borderCollapse(&bsBuf);
		g_sStyleAsText += L";border-collapse:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_borderColor(&bsBuf);
		g_sStyleAsText += L";border-color:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_borderStyle(&bsBuf);
		g_sStyleAsText += L";border-style:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_borderWidth(&bsBuf);
		g_sStyleAsText += L";border-width:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle->get_bottom(&vtBuf);
		g_sStyleAsText += L";bottom:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		pStyle->get_clear(&bsBuf);
		g_sStyleAsText += L";clear:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle->get_color(&vtBuf);
		g_sStyleAsText += L";color:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();


		pStyle->get_cursor(&bsBuf);
		g_sStyleAsText += L";cursor:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_direction(&bsBuf);
		g_sStyleAsText += L";direction:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_display(&bsBuf);
		g_sStyleAsText += L";display:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}
		
		pStyle->get_fontWeight(&vtBuf);
        g_sStyleAsText += L";font-weight:";
		wchar_t sLong[33];
		g_sStyleAsText += ::_ltow(vtBuf.lVal,sLong,10);
		
		vtBuf.vt = VT_BSTR;
		pStyle->get_height(&vtBuf);
		g_sStyleAsText += L";height:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();


		vtBuf.vt = VT_BSTR;
		pStyle->get_layoutGridChar(&vtBuf);
		g_sStyleAsText += L";layout-grid-char:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();


		pStyle->get_layoutGridMode(&bsBuf);
		g_sStyleAsText += L";layout-grid-mode:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_layoutGridType(&bsBuf);
		g_sStyleAsText += L";layout-grid-type:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle->get_left(&vtBuf);
		g_sStyleAsText += L";left:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();


		vtBuf.vt = VT_BSTR;
		pStyle->get_letterSpacing(&vtBuf);
		g_sStyleAsText += L";letter-spacing:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		pStyle->get_lineBreak(&bsBuf);
		g_sStyleAsText += L";line-break:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle->get_lineHeight(&vtBuf);
		g_sStyleAsText += L";line-height:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		pStyle->get_listStyleImage(&bsBuf);
		g_sStyleAsText += L";list-style-image:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_listStylePosition(&bsBuf);
		g_sStyleAsText += L";list-style-position:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_listStyleType(&bsBuf);
		g_sStyleAsText += L";list-style-type:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_margin(&bsBuf);
		g_sStyleAsText += L";margin:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_overflow(&bsBuf);
		g_sStyleAsText += L";overflow:";
		if(bsBuf) { 
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_padding(&bsBuf);
		g_sStyleAsText += L";padding:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_pageBreakAfter(&bsBuf);
		g_sStyleAsText += L";page-break-after:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_pageBreakBefore(&bsBuf);
		g_sStyleAsText += L";page-break-before:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_position(&bsBuf);
		g_sStyleAsText += L";position:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}
		vtBuf.vt = VT_BSTR;
		pStyle->get_right(&vtBuf);
		g_sStyleAsText += L";right:";
		if(vtBuf.bstrVal) 
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		pStyle->get_styleFloat(&bsBuf);
		g_sStyleAsText += L";float:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_tableLayout(&bsBuf);
		g_sStyleAsText += L";table-layout:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_textAlign(&bsBuf);
		g_sStyleAsText += L";text-align:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_textAutospace(&bsBuf);
		g_sStyleAsText += L";text-autospace:";
		if(bsBuf) { 
            g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_textDecoration(&bsBuf);
		g_sStyleAsText += L";text-decoration:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle->get_textIndent(&vtBuf);
		g_sStyleAsText += L";text-indent:";
		if(vtBuf.bstrVal) 
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();


		pStyle->get_textJustify(&bsBuf);
		g_sStyleAsText += L";text-justify:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle->get_textTransform(&bsBuf);
		g_sStyleAsText += L";text-transform:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle->get_top(&vtBuf);
		g_sStyleAsText += L";top:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();


		pStyle->get_unicodeBidi(&bsBuf);
		g_sStyleAsText += L";unicode-bidi:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle->get_verticalAlign(&vtBuf);
		g_sStyleAsText += L";vertical-align:";
		if(vtBuf.bstrVal) 
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		pStyle->get_visibility(&bsBuf);
		g_sStyleAsText += L";visibility:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle->get_width(&vtBuf);
		g_sStyleAsText += L";width:";
		if(vtBuf.bstrVal) 
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		pStyle->get_wordBreak(&bsBuf);
		g_sStyleAsText += L";word-break:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}
/*
		vtBuf.vt = VT_BSTR;
		pStyle->get_zIndex(&vtBuf);
		g_sStyleAsText += L";z-index:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();
*/
		// Code reinstated Bug 271
		try {
			pStyle->get_fontFamily(&bsBuf);
			g_sStyleAsText += L";font-family:";
			if(bsBuf) {
				g_sStyleAsText += bsBuf;
				::SysFreeString(bsBuf);
			}
		}
		catch(...) {
			ASSERT(!CATCH_COPYSTYLE_FUCKUPS);
		}

		try {
			vtBuf.vt = VT_BSTR;
			pStyle->get_fontSize(&vtBuf);
			g_sStyleAsText += L";font-size:";
			if(vtBuf.bstrVal) 
				g_sStyleAsText += vtBuf.bstrVal;
			vtBuf.Clear();
		}
		catch(...) {
			ASSERT(!CATCH_COPYSTYLE_FUCKUPS);
		}

		try {
			pStyle->get_fontStyle(&bsBuf);
			g_sStyleAsText += L";font-style:";
			if(bsBuf) {
				g_sStyleAsText += bsBuf;
				::SysFreeString(bsBuf);
			}
		}
		catch(...) {
			ASSERT(!CATCH_COPYSTYLE_FUCKUPS);
		}

		try {
			pStyle->get_fontVariant(&bsBuf);
			g_sStyleAsText += L";font-variant:";
			if(bsBuf) {
				g_sStyleAsText += bsBuf;
				::SysFreeString(bsBuf);
			}
		}
		catch(...) {
			ASSERT(!CATCH_COPYSTYLE_FUCKUPS);
		}

		try {
			pStyle->get_imeMode(&bsBuf);
			g_sStyleAsText += L";ime-mode:";
			if(bsBuf) {
				g_sStyleAsText += bsBuf;
				::SysFreeString(bsBuf);
			}
		}
		catch(...) {
			ASSERT(!CATCH_COPYSTYLE_FUCKUPS);
		}

		try {
			pStyle->get_rubyAlign(&bsBuf);
			g_sStyleAsText += L";ruby-align:";
			if(bsBuf) {
				g_sStyleAsText += bsBuf;
				::SysFreeString(bsBuf);
			}
		}
		catch(...) {
			ASSERT(!CATCH_COPYSTYLE_FUCKUPS);
		}

		try {
			pStyle->get_rubyOverhang(&bsBuf);
			g_sStyleAsText += L";ruby-overhang:";
			if(bsBuf) {
				g_sStyleAsText += bsBuf;
				::SysFreeString(bsBuf);
			}
		}
		catch(...) {
			ASSERT(!CATCH_COPYSTYLE_FUCKUPS);
		}

		try {
			pStyle->get_rubyPosition(&bsBuf);
			g_sStyleAsText += L";ruby-position:";
			if(bsBuf) {
				g_sStyleAsText += bsBuf;
				::SysFreeString(bsBuf);
			}
		}
		catch(...) {
			ASSERT(!CATCH_COPYSTYLE_FUCKUPS);
		}

	}

	CComQIPtr<IHTMLCurrentStyle2> pStyle2 = pStyle;
	if(SUCCEEDED(hr) && pStyle2)
	{
	//BEGIN: IHTMLCurrentStyle2 properties
		pStyle2->get_layoutFlow(&bsBuf);
		g_sStyleAsText += L";layout-flow:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle2->get_scrollbar3dLightColor(&vtBuf);
		g_sStyleAsText += L";scrollbar-3dlight-color:";
		if(vtBuf.bstrVal) 
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();


		vtBuf.vt = VT_BSTR;
		pStyle2->get_scrollbarArrowColor(&vtBuf);
		g_sStyleAsText += L";scrollbar-arrow-color:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();


		vtBuf.vt = VT_BSTR;
		pStyle2->get_scrollbarBaseColor(&vtBuf);
		g_sStyleAsText += L";scrollbar-base-color:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		vtBuf.vt = VT_BSTR;
		pStyle2->get_scrollbarDarkShadowColor(&vtBuf);
		g_sStyleAsText += L";scrollbar-darkshadow-color:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		vtBuf.vt = VT_BSTR;
		pStyle2->get_scrollbarFaceColor(&vtBuf);
		g_sStyleAsText += L";scrollbar-face-color:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		vtBuf.vt = VT_BSTR;
		pStyle2->get_scrollbarHighlightColor(&vtBuf);
		g_sStyleAsText += L";scrollbar-highlight-color:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		vtBuf.vt = VT_BSTR;
		pStyle2->get_scrollbarShadowColor(&vtBuf);
		g_sStyleAsText += L";scrollbar-shadow-color:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		vtBuf.vt = VT_BSTR;
		pStyle2->get_scrollbarTrackColor(&vtBuf);
		g_sStyleAsText += L";scrollbar-track-color:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();


		pStyle2->get_textAlignLast(&bsBuf);
		g_sStyleAsText += L";text-align-last:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle2->get_textKashidaSpace(&vtBuf);
		g_sStyleAsText += L";text-kashida-space:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		pStyle2->get_textUnderlinePosition(&bsBuf);
		g_sStyleAsText += L";text-underline-position:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle2->get_wordWrap(&bsBuf);
		g_sStyleAsText += L";word-wrap:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle2->get_writingMode(&bsBuf);
		g_sStyleAsText += L";writing-mode:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle2->get_zoom(&vtBuf);
		g_sStyleAsText += L";zoom:";
		if(vtBuf.bstrVal) 
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

	}

	CComQIPtr<IHTMLCurrentStyle3> pStyle3;
	if(pStyle2)
		pStyle3 = pStyle2;
	if(pStyle3)
	{
		vtBuf.vt = VT_BSTR;
		pStyle3->get_minHeight(&vtBuf);
		g_sStyleAsText += L";min-height:";
		if(vtBuf.bstrVal)
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

		pStyle3->get_textOverflow(&bsBuf);
		g_sStyleAsText += L";text-overflow:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		pStyle3->get_whiteSpace(&bsBuf);
		g_sStyleAsText += L";white-space:";
		if(bsBuf) {
			g_sStyleAsText += bsBuf;
			::SysFreeString(bsBuf);
		}

		vtBuf.vt = VT_BSTR;
		pStyle3->get_wordSpacing(&vtBuf);
		g_sStyleAsText += L";word-spacing:";
		if(vtBuf.bstrVal) 
			g_sStyleAsText += vtBuf.bstrVal;
		vtBuf.Clear();

	}

	// Bug 880 - Allocate a BSTR from the global string. Its a little quicker if we give it 
	// the size of the string.
	*pbsRetVal = ::SysAllocStringLen(g_sStyleAsText.c_str(), g_sStyleAsText.length() + 1);
	
	return hr;
}

// Perform any initialisation specific to this particular behaviour.  
HRESULT CBinaryBehavior::InitBehaviour()
{
	return S_OK;
}

// sets the various properties related to viewlink on a behaviour
HRESULT CBinaryBehavior::SetViewlinkProperties(IHTMLDocument * pVLDoc , VARIANT_BOOL bInheritStyle, VARIANT_BOOL bTabstop, VARIANT_BOOL bMasterTab)
{
	//Insert the document.
	HRESULT hr = E_FAIL;
	if(m_pDefaults) {
		hr = m_pDefaults->putref_viewLink(pVLDoc);
		//means the top level has the same style as the master
		hr = m_pDefaults->put_viewInheritStyle(bInheritStyle);
		//means that we participate in the tabbing order
		hr = m_pDefaults->put_tabStop(bTabstop);
		//means that the top level element is transparent in the
		//	tabbing order.
		hr = m_pDefaults->put_viewMasterTab(bMasterTab);
		CComPtr<IHTMLElement> pMaster;
		GetMasterElement(&pMaster);
		if(pMaster)
		{
			CComBSTR sAttrName("elementContainsViewlink");
			CComBSTR sTrue("true");
			pMaster->setAttribute(sAttrName,CComVariant(sTrue),3);
			pMaster->setAttribute(L"viewlinkDocument",CComVariant(pVLDoc),3);
		}
	}
	return hr;
}


HRESULT CBinaryBehavior::GetNamedBehavior(BSTR sName, IDispatch * pDispNode, IElementBehavior ** ppBehavior)
{
	HRESULT hr = E_FAIL;
	DISPID dispid;
	hr = pDispNode->GetIDsOfNames
	(
		IID_NULL,
		&sName,
		1,
		LOCALE_SYSTEM_DEFAULT,
		&dispid
	);
	if(SUCCEEDED(hr) && dispid)
	{
		VARIANT vtResult;
		DISPPARAMS params;
		hr = pDispNode->Invoke
		(
			dispid,	IID_NULL,
			LOCALE_SYSTEM_DEFAULT,
			DISPATCH_PROPERTYGET,
			&params,
			&vtResult,	0,	0
		);

		if(VT_DISPATCH == vtResult.vt)
		{
			hr = vtResult.pdispVal->QueryInterface(IID_IElementBehavior,reinterpret_cast<void**>(ppBehavior));
			vtResult.pdispVal->Release();
		}

	}
	return hr;
}

	STDMETHODIMP CBinaryBehavior::addEventListener(BSTR /*type*/, IEventListener * /*listener*/, BOOL /*useCapture*/)
	{
		return E_NOTIMPL;
	}
	STDMETHODIMP CBinaryBehavior::removeEventListener(BSTR /*type*/, IEventListener * /*listener*/, BOOL /*useCapture*/)
	{
		return E_NOTIMPL;
	}
	STDMETHODIMP CBinaryBehavior::dispatchEvent(IDOMEvent * evt,BOOL * pbCancelled)
	{
		CComBSTR sType;
		HRESULT hr = evt->get_type(&sType);
		if(SUCCEEDED(hr) && sType)
		{
			long lCookie;
			hr = m_pSiteOM->GetEventCookie(sType,&lCookie);
			if(S_OK == hr)
			{
				//TODO: translate properties from IDOMEvent into IHTMLEventObj
				hr = m_pSiteOM->FireEvent(lCookie,0);
				if(pbCancelled)
					*pbCancelled = false;
			}
		}
		return hr;
	}

HRESULT WINAPI CBinaryBehavior_MasterQueryInterface(void* pv, REFIID riid, LPVOID* ppv, DWORD /*dw*/)
{
	HRESULT hr = E_NOINTERFACE;
	CBinaryBehavior * pBehaviour  = reinterpret_cast<CBinaryBehavior*>(pv);
	//Fetch the masterElement.
	CComPtr<IHTMLElement> pEl;
	pBehaviour->GetMasterElement(&pEl);
	//Query the masterElement's interface
	if(pEl)
		hr = pEl->QueryInterface(riid,ppv);
	return hr;
}
